﻿using DataAccess;
using Microsoft.Office.Interop.Word;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Serialization;

namespace DataProcess
{
    [Serializable]
    public class Article
    {
        public static DataAccess.Database Db { get; set; }

        public static string[] UnCommonWords = { "丝谏.gif", "二又虫.gif", "人南.gif", "口父.gif", "口苏.gif", "圭虫.gif", "彳缶阝.gif", "月忍.gif", "木党.gif", "木梨.gif", "木聂.gif", "木肴.gif", "木规.gif", "束虫.gif", "果力.gif", "犭卂.gif", "犭炖.gif", "王南.gif", "病颓.gif", "空氣.gif", "竹敛.gif", "艹攴.gif", "艹陈.gif", "草与.gif", "草为.gif", "草女乇.gif", "草戾.gif", "草易.gif", "草睆.gif", "草移.gif", "草至.gif", "草虑.gif", "草蟳.gif", "草覆.gif", "草诸.gif", "草赣.gif", "草门可.gif", "草间月.gif", "草闾.gif", "虫傅.gif", "虫瑞.gif", "虫祁.gif", "虫长.gif", "革庶.gif", "韭番.gif", "马粦.gif", "鱼比.gif" };

        private ParagraphList paragraphs;
        private Paragraph root;
        List<ArticleImage> Images = new List<ArticleImage>();
        #region 私有常量的定义

        /// <summary>
        /// 一级段落名称开始标记
        /// </summary>
        private const string paragraphLevel1StartFlag = "【";

        /// <summary>
        /// 一级段落名称结束标记
        /// </summary>
        private const string paragraphLevel1EndFlag = "】";

        /// <summary>
        /// 二级段落名称开始标记
        /// </summary>
        private const string paragraphLevel2StartFlag = "[";

        /// <summary>
        /// 二级段落名称结束标记
        /// </summary>
        private const string paragraphLevel2EndFlag = "]";

        private const string NameRegex = "※.*?※|\\(.*?\\)|《.*?》";
        #endregion

        #region 私有字段定义
        /// <summary>
        /// 用于延时转换Html标题
        /// </summary>
        private string _title = null;

        internal Dictionary<object, Paragraph> allParagraph = new Dictionary<object, Paragraph>();

        /// <summary>
        /// 原始文本标题名称
        /// </summary>
        private string _orgTitle = null;

        private int _articleId = -1;

        /// <summary>
        /// 文件名
        /// </summary>
        private string fileName = string.Empty;

        #endregion


        /// <summary>
        /// 文章在数据库中的id
        /// </summary>
        [XmlIgnore]
        public int ArticleId
        {
            get
            {
                return _articleId;
            }
            set
            {
                _articleId = value;
            }
        }

        /// <summary>
        /// Html文章标题（上下标为HTML标签）
        /// </summary>
        public string Title
        {
            get
            {
                return _title;
            }
            set { _title = value; }
        }

        /// <summary>
        /// 段落列表
        /// </summary>
        public ParagraphList Paragraphs
        {
            get
            {
                if (this.paragraphs == null)
                {
                    this.paragraphs = new ParagraphList(this.root);
                }
                return this.paragraphs;
            }
        }

        public static void Dispose()
        {

        }

        public Article()
        {
            this.root = new Paragraph(this);
        }

        public Article(string articleFile)
            : this()
        {
            this.Title = Path.GetFileNameWithoutExtension(articleFile);

            if (!File.Exists(articleFile))
            {
                Debug.WriteLine("药物名称：{0}；路径：{1}未找到文件", Title, fileName);
                return;//不存在时，直接返回
            }
            fileName = articleFile;

            string imageDir = Path.Combine(Path.GetDirectoryName(this.fileName), "images");
            List<string> imagesSrc = new List<string>();


            #region 读取段落内容
            Paragraph lastFirstP = null;
            Paragraph lastSecondP = null;
            StringBuilder contentBuilder = new StringBuilder();
            int lineNumber = 0;
            DateTime upTime = DateTime.Now;
            using (StreamReader sr = new StreamReader(fileName, System.Text.Encoding.Default, true))
            {
                while (sr.Peek() > -1)
                {
                    string line = sr.ReadLine();
                    lineNumber++;
                    //用户判断最后一次设置内容的段落，这里先判断最后一次设置内容的二级段落
                    Paragraph lastContentParagraph = null;
                    if (lastSecondP != null)
                    {
                        lastContentParagraph = lastSecondP;
                    }
                    else if (lastFirstP != null)
                    {
                        lastContentParagraph = lastFirstP;
                    }
                    if (line.StartsWith(paragraphLevel1StartFlag) && line.EndsWith(paragraphLevel1EndFlag))
                    {
                        if (lastFirstP != null && lastFirstP.Children.Count == 0)
                        {
                            //lastFirstP.Children = null;
                        }
                        if (lastContentParagraph != null)
                        {
                            lastContentParagraph.OrgContent = GetLackImages(contentBuilder.ToString().TrimEnd('\r', '\n'));

                            contentBuilder.Clear();
                        }
                        lastFirstP = new Paragraph();
                        //lastFirstP.Children = new List<Paragraph>();
                        lastFirstP.Title = line.Substring(paragraphLevel1StartFlag.Length, line.Length - paragraphLevel1StartFlag.Length - paragraphLevel1EndFlag.Length);
                        this.Paragraphs.Add(lastFirstP);
                        lastSecondP = null;
                        continue;
                    }
                    if (line.StartsWith(paragraphLevel2StartFlag) && line.EndsWith(paragraphLevel2EndFlag))
                    {
                        if (lastContentParagraph != null)
                        {
                            lastContentParagraph.OrgContent = GetLackImages(contentBuilder.ToString().TrimEnd('\r', '\n'));
                            contentBuilder.Clear();
                        }
                        lastSecondP = new Paragraph();
                        lastSecondP.Title = line.Substring(paragraphLevel2StartFlag.Length, line.Length - paragraphLevel2StartFlag.Length - paragraphLevel2EndFlag.Length);
                        lastSecondP.Parent = lastFirstP;
                        lastFirstP.Children.Add(lastSecondP);
                        continue;
                    }

                    #region 数据异常检查
                    if (line.StartsWith("[") || line.StartsWith("【"))
                    {
                        Debug.WriteLine("段落标记不匹配：{0}；段落：{1}", Title, line);
                    }
                    if (lastFirstP == null)
                    {
                        Debug.WriteLine("段落开始之前已经有内容：{0}；内容：{1}", Title, line);
                        continue;
                    }
                    if (line.Trim().StartsWith("[") || line.Trim().StartsWith("【"))
                    {
                        Debug.WriteLine("疑似段落：{0}；段落：{1}", Title, line);
                    }
                    if (line.Trim().IndexOfAny(new char[] { '【', '】' }) > -1)
                    {
                        Debug.WriteLine("段落中存在段落标记符号：{0}；段落：{1}", Title, line);
                    }
                    if ((line.Length - line.Replace("※", string.Empty).Length) % 2 != 0)
                    {
                        Debug.WriteLine("段落中的※符号不成对：{0}；段落：{1}", Title, lastFirstP.Title);
                    }
                    if ((line.Length - line.Replace("★", string.Empty).Length) % 2 != 0)
                    {
                        Debug.WriteLine("段落中的★符号不成对：{0}；段落：{1}", Title, lastFirstP.Title);
                    }
                    if ((line.Length - line.Replace("☆", string.Empty).Length) % 2 != 0)
                    {
                        Debug.WriteLine("段落中的☆符号不成对：{0}；段落：{1}", Title, lastFirstP.Title);
                    }
                    #endregion
                    contentBuilder.AppendLine(line);
                }
                if (contentBuilder.Length > 0)
                {
                    if (lastSecondP != null)
                    {
                        lastSecondP.OrgContent = GetLackImages(contentBuilder.ToString().TrimEnd('\r', '\n'));
                        contentBuilder.Clear();
                    }
                    else if (lastFirstP != null)
                    {
                        lastFirstP.OrgContent = GetLackImages(contentBuilder.ToString().TrimEnd('\r', '\n'));
                        contentBuilder.Clear();
                    }
                }
            }
            #endregion
        }

        /// <summary>
        /// 保存到数据库
        /// </summary>
        public void SaveToDatabase(bool getNames = true)
        {
            //1：插入主表
            //2：插入内容表
            //3：提取chm_name
            //4：插入名称表
            //5：插入图片表
            //6：处理图片表中的旧图片

            var checkid = Db.ExecuteScalar("SELECT chmid FROM chm_main WHERE chm_title=?", new Parameter("title", Title));
            if (checkid != null && !(checkid is DBNull))
            {
                ArticleId = (int)checkid;
            }
            var tran = Db.BeginTransaction();
            if (ArticleId == 0)
            {
                tran.ExecuteNonQuery("insert into chm_main (chm_title) values(?)", new Parameter("title", Title));
                ArticleId = (int)tran.ExecuteScalar("select  @@identity");
            }

            int phnumber1 = 0;

            foreach (var ph1 in this.Paragraphs)
            {
                if (string.IsNullOrEmpty(ph1.ReleaseContent) && ph1.Children.Count(ph => !string.IsNullOrEmpty(ph.ReleaseContent)) == 0)
                {
                    continue;
                }

                phnumber1++;
                tran.ExecuteNonQuery("insert into chm_content (chmid,chm_title,chm_phname,chm_seqnum,chm_seqnum2,chm_content) values(?,?,?,?,?,?)", new Parameter("chmid", this.ArticleId), new Parameter("title", this.Title), new Parameter("chm_phname", ph1.Title), new Parameter("chm_seqnum", phnumber1), new Parameter("chm_seqnum2", 0), new Parameter("chm_content", ph1.ReleaseContent));
                if (ph1.Title != "饮片名称" && !string.IsNullOrWhiteSpace(ph1.ReleaseContent) && ph1.Children.Count > 0)
                {
                    Debug.WriteLine("一级段落有内容，同时存在二级段落文章：{0}；段落：{1}", this.Title, ph1.Title);
                }
                int phnumber2 = 0;

                foreach (var ph2 in ph1.Children)
                {
                    if (string.IsNullOrEmpty(ph2.ReleaseContent))
                    {
                        continue;
                    }
                    phnumber2++;
                    tran.ExecuteNonQuery("insert into chm_content (chmid,chm_title,chm_phname,chm_seqnum,chm_seqnum2,chm_content) values(?,?,?,?,?,?)", new Parameter("chmid", this.ArticleId), new Parameter("title", this.Title), new Parameter("chm_phname", ph2.Title), new Parameter("chm_seqnum", phnumber1), new Parameter("chm_seqnum2", phnumber2), new Parameter("chm_content", ph2.ReleaseContent));
                }
            }


            if (getNames)
            {
                var names = GetDrugNames();
                foreach (var name in names)
                {
                    tran.ExecuteNonQuery("insert into chm_name (chmid,chm_name,pinyin,name_type) values(?,?,?,?)", new Parameter("chmid", this.ArticleId), new Parameter("chm_name", name.Name), new Parameter("pinyin", name.Pinyin), new Parameter("name_type", name.Type));
                }
            }
            foreach (var image in Images)
            {
                tran.ExecuteNonQuery("insert into chm_images (chmid,filename,imagestream) values(?,?,?)", new Parameter("chmid", this.ArticleId), new Parameter("imagename", image.ImageName), new Parameter("imagestream", image.ImageStream));
            }
            tran.Commit();
            tran.Dispose();

        }



        /// <summary>
        /// 获取内容中的图片
        /// </summary>
        /// <param name="content"></param>
        /// <returns></returns>
        public string GetLackImages(string content)
        {

            if (string.IsNullOrWhiteSpace(content) || content.IndexOf("<img") == -1)
            {
                return content;
            }

            string imageDir = Path.Combine(Path.GetDirectoryName(this.fileName), "images");


            content = Regex.Replace(content, "<img[^<>]*\\s+src=(?<Quote>[\\\"']?)(?<value>.+?)\\k<Quote>\\s+[^<>]*?>", match =>
            {
                string src = Path.GetFileName(match.Groups[2].Value);

                int index = Array.IndexOf(UnCommonWords, src);
                string imageName = src;
                if (index > -1)
                {
                    imageName = string.Format("uncommon_{0}.gif", index + 1);
                }
                else
                {
                    Debug.WriteLine("特殊图片：{0}；图片：{1}", this.Title, src);
                }
                if (!Images.Exists(img => img.ImageName.Equals(imageName, StringComparison.CurrentCultureIgnoreCase)))
                {
                    string imagePath = Path.Combine(imageDir, src);
                    if (File.Exists(imagePath))
                    {
                        Images.Add(new ArticleImage { ImageName = imageName, ImageStream = File.ReadAllBytes(imagePath) });
                    }
                    else
                    {
                        Debug.WriteLine("图片未找到：{0}；图片：{1}", this.Title, src);
                    }
                }
                return string.Format("<img src=\"{0}\" />", imageName);
            }, RegexOptions.IgnoreCase);

            return content;
        }

        /// <summary>
        /// 获取中药名称
        /// </summary>
        /// <returns></returns>
        public DrugName[] GetDrugNames()
        {
            List<DrugName> names = new List<DrugName>();
            var pName = allParagraph.Values.FirstOrDefault(p => p.Title == "饮片名称");

            if (pName != null)
            {
                string content = Regex.Replace(pName.OrgContent.Replace("\r\n", string.Empty), NameRegex, string.Empty);
                DrugName name = new DrugName { Name = content, Type = "正名" };
                pName = allParagraph.Values.FirstOrDefault(p => p.Title == "汉语拼音");
                if (pName != null)
                {
                    name.Pinyin = Regex.Replace(pName.OrgContent.Replace("\r\n", string.Empty), NameRegex, string.Empty);
                    names.Add(name);
                }
                else
                {
                    Debug.WriteLine("无法找到[汉语拼音]段落", this.Title);
                }
            }
            else
            {
                Debug.WriteLine("无法找到【饮片名称】段落", this.Title);
            }

            pName = allParagraph.Values.FirstOrDefault(p => p.Title == "拉丁名");
            if (pName != null)
            {
                string content = Regex.Replace(pName.OrgContent.Replace("\r\n", string.Empty), NameRegex, string.Empty);
                DrugName name = new DrugName { Name = content, Type = "拉丁名" };
                names.Add(name);
            }
            pName = allParagraph.Values.FirstOrDefault(p => p.Title == "异名");
            if (pName != null)
            {
                string content = Regex.Replace(pName.OrgContent.Replace("\r\n", string.Empty).TrimEnd('。'), NameRegex, string.Empty);
                var otherNames = content.Split(new char[] { '；', '、', '。' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var item in otherNames)
                {
                    DrugName name = new DrugName { Name = item, Type = "异名" };
                    names.Add(name);
                }
            }
            return names.ToArray();
        }
    }
}
